package com.system;

import android.opengl.GLES30;
import android.opengl.Matrix;
import android.os.Build;
import android.support.annotation.RequiresApi;

import com.graphics.element.AbsSceneNode;
import com.math3d.MatrixUtil;
import com.math3d.Vector2f;
import com.math3d.Vector2fv;
import com.math3d.Vector3fv;
import com.math3d.Vector4fv;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;

/**
 * @Author: clm
 * @Date: 2018-10-15
 */

public class Camera extends AbsSceneNode{
    //视角
    public float mViewAngle = 45.0f;
    public float mNear = 0.1f;
    public float mFar = 100.0f;
    //视角一半与单位朝向向量的点乘
    public double mViewDot;
    //用于存放视图矩阵，投影矩阵以及视图*投影矩阵的uniform缓存
    protected int[] matrix_ubo;
    protected FloatBuffer mVBF, mPBF;
    //视图矩阵
    public float mV_matrix[] = new float[16];
    public float mP_matrix[];
    //旋转矩阵
    public float mCameraRotateMat4[] = new float[16];
    public Vector4fv eye = new Vector4fv(0.0f, 0.0f, 0.0f, 1.0f);
    public Vector4fv at = new Vector4fv(0.0f, 0.0f, -1.0f, 1.0f);
    public Vector4fv up = new Vector4fv(0.0f, 1.0f, 0.0f, 1.0f);
    public Vector4fv dir = new Vector4fv(0.0f, 0.0f, -1.0f, 1.0f);
    //用于保存归一化朝向向量
    public Vector2fv at2f;
    //x轴
    public Vector3fv xAxis = new Vector3fv(1.0f, 0.0f, 0.0f);
    //y轴
    public Vector3fv yAxis = new Vector3fv(0.0f, 1.0f, 0.0f);
    //用于计算水平/垂直偏移量
    public float lastX, lastY;
    public float detaX, detaY;

    /**
     * 创建Uniform缓存用于提交v,p矩阵
     */
    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
    protected void initUBO(){
        //创建uniform缓存
        matrix_ubo = new int[1];
        GLES30.glGenBuffers(1, matrix_ubo, 0);
        GLES30.glBindBuffer(GLES30.GL_UNIFORM_BUFFER, matrix_ubo[0]);
        GLES30.glBufferData(GLES30.GL_UNIFORM_BUFFER, 3 * MatrixUtil.mat4_byte_length, null, GLES30.GL_STATIC_DRAW);
        GLES30.glBindBufferRange(GLES30.GL_UNIFORM_BUFFER, 0x001, matrix_ubo[0], 0, 3 * MatrixUtil.mat4_byte_length);
        GLES30.glBindBuffer(GLES30.GL_UNIFORM_BUFFER, 0);
        //创建数据
        mVBF = ByteBuffer.allocateDirect(MatrixUtil.mat4_byte_length).order(ByteOrder.nativeOrder()).asFloatBuffer();
        mVBF.position(0);
        mPBF = ByteBuffer.allocateDirect(MatrixUtil.mat4_byte_length).order(ByteOrder.nativeOrder()).asFloatBuffer();
        mPBF.put(mP_matrix).position(0);
    }
    //绕x,y轴旋转弧度
    public Camera(){
        super("camera");
        double s = (mViewAngle / 2.0f) * Math.PI / 180;
        mViewDot = Math.cos(s);
        MatrixUtil.normalize(mCameraRotateMat4);
        Matrix.setLookAtM(mV_matrix, 0, eye.getVec()[0], eye.getVec()[1], eye.getVec()[2], at.getVec()[0], at.getVec()[1], at.getVec()[2], up.getVec()[0], up.getVec()[1], up.getVec()[2]);
    }

    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
    public void setP_matrix(float[] p_matrix) {
        mP_matrix = p_matrix;
        initUBO();
    }

    @Override
    public void update(float exTime) {
        super.update(exTime);
        mVisible = false;           //相机不需要渲染
        updateCamera();
        //在这里统一提交v,p矩阵到缓存中
        mVBF.clear();
        mVBF.put(mV_matrix).position(0);
        GLES30.glBindBuffer(GLES30.GL_UNIFORM_BUFFER, matrix_ubo[0]);
        GLES30.glBufferSubData(GLES30.GL_UNIFORM_BUFFER, 0, MatrixUtil.mat4_byte_length, mVBF);
        GLES30.glBufferSubData(GLES30.GL_UNIFORM_BUFFER, MatrixUtil.mat4_byte_length, MatrixUtil.mat4_byte_length, mPBF);
        GLES30.glBindBuffer(GLES30.GL_UNIFORM_BUFFER, 0);
    }

    public final void updateCamera() {
        Vector4fv result = new Vector4fv();
        Matrix.multiplyMV(result.getVec(), 0, mCameraRotateMat4, 0, dir.getVec(), 0);
        //eye+result=at
        eye.fastAdd(at.getVec(), result);
        Matrix.setLookAtM(mV_matrix, 0, eye.getVec()[0], eye.getVec()[1], eye.getVec()[2], at.getVec()[0], at.getVec()[1], at.getVec()[2], up.getVec()[0], up.getVec()[1], up.getVec()[2]);
        scaleViewAt();
    }

    /**
     * 归一化朝向向量,将结果保存到at2f
     */
    public final void scaleViewAt(){
        //归一化朝向向量(我们只需要x-z平面朝向)
        Vector4fv temp = at.sub(eye);
        at2f = new Vector2fv(temp.vec[0], temp.vec[2]);
        at2f.normalize();
    }

    /**
     * 计算视锥在视平面x-z的四个点
     */
    public final void scaleViewPotAtXZ(){
        //归一化朝向向量(我们只需要x-z平面朝向)
        Vector2fv at2f = new Vector2fv(at.vec[0], at.vec[1]);
        at2f.normalize();
        //计算远截面2个顶点0
        at2f.applyTo(20);
        //计算近截面2个顶点
        double a = 22.5f * Math.PI / 180;
        double s = Math.cos(a);
    }
}
